package org.lites.dcimmodifier;

import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.*;
import java.time.*;

/**
 * 文件名时间戳提取器
 */
public class TimeStampExtractor {
    private static final String MATCH_PATTERN = "" +
            "\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2}|" +
            "\\d{14}|" +
            "\\d{13,16}|" +
            "\\d{4}-\\d{2}-\\d{2}|" +
            "\\d{8}";
    private static final String OUT_PATTERN = "yyyy:MM:dd HH:mm:ss";

    private static final String[] TIME_PATTERNS = {
            "yyyy-MM-dd-HH-mm-ss",
            "yyyyMMddHHmmss",
            "TIMESTAMP",
            "yyyy-MM-dd",
            "yyyyMMdd"
    };
    /**
     * 测试提取有效时间戳
     * @param args
     */
    public static void main(String[] args) {
        String[] filenames = {
                "20201022_20211029_1514444444411.mp4", // ✅ 提取时间: 2017:12:28 07:00:44
                "wx_camera_1740206218389.mp4",   // ✅ 提取时间: 2025:02:22 06:36:58
                "test_253402300799999.mp4",      // ✅ 提取时间: 2772:12:31 16:47:59
                "video_946684800000.mp4",        // ❌ 无效时间戳
                "badfile_12345.mp4",             // ❌ 无效时间戳
                "prefix_0999999999999.jpg",      // ✅ 提取时间: 2001:09:09 01:46:39
                "sample_1735689599999.dat",      // ✅ 提取时间: 2024:12:31 23:59:59
                "invalid_9999999999999999.txt",   // ❌ 无效时间戳
                "file_2021-03-22-12-05-30.mp4",  // ✅ 提取时间: 2021:03:22 12:05:30
                "test_2021-03-22.mp4"            // ✅ 提取时间: 2021:03:22 00:00:00
        };

        for (String filename : filenames) {
            String validTimestamp = extractValidTimestamp(filename);
            System.out.println("文件: " + filename + " | " +
                    (validTimestamp != null ? "✅ 提取时间: " + validTimestamp : "❌ 无效时间戳"));
        }
    }

    /**
     * 提取文件名中最早的有效时间戳
     * @param filename 文件名字符串
     * @return 最早的时间戳
     */
    public static String extractValidTimestamp(String filename) {
        // 提取文件名中的所有符合条件的时间戳
        List<String> validTimestamps = extractValidTimestamps(filename);

        // 如果没有有效时间戳，返回null
        if (validTimestamps.isEmpty()) {
            return null;
        }

        // 转换所有有效的时间戳为 Instant 类型，并找到日期最早的时间戳
        Optional<String> earliestTimestamp = validTimestamps.stream()
                .min(Comparator.comparing(TimeStampExtractor::toInstant));

        return earliestTimestamp.orElse(null);
    }
    /**
     * 将时间戳字符串转换为 long 类型
     * @param str 时间戳字符串
     * @return long 类型
     */
    public static Optional<Long> safeParseLong(String str) {
        try {
            return Optional.of(Long.parseLong(str));
        } catch (NumberFormatException e) {
            return Optional.empty();
        }
    }
    /**
     * 提取文件名中的所有有效时间戳（日期和时间戳两种格式）
     * @param filename 文件名字符串
     * @return 所有有效时间戳
     */
    public static List<String> extractValidTimestamps(String filename) {
        List<String> timestamps = new ArrayList<>();

        // 正则表达式匹配时间戳（支持yyyyMMdd格式、yyyyMMddHHmmss格式、yyyy-MM-dd格式和yyyy-MM-dd-HH-mm-ss格式）
        Pattern pattern = Pattern.compile(MATCH_PATTERN);
        Matcher matcher = pattern.matcher(filename);

        while (matcher.find()) {
            String timestampStr = matcher.group();
            for (String time_pattern : TIME_PATTERNS) {

                if(time_pattern.equals("TIMESTAMP")){

                    if (isValidTimestamp(timestampStr)) {
                        String paddedTimestamp = String.format("%16s", timestampStr).replace(' ', '0'); // 补齐16位
                        Instant instant = Instant.ofEpochMilli(Long.parseLong(paddedTimestamp));
                        ZonedDateTime dateTime = instant.atZone(ZoneOffset.UTC);
                        // 定义格式化模式
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(OUT_PATTERN);
                        // 格式化 ZonedDateTime
                        timestampStr = dateTime.format(formatter);
                        timestamps.add(timestampStr); // 时间戳格式
                        break;
                    }
                }
                else{
                    if (isValidTime(timestampStr,time_pattern)) {
                        timestamps.add(formatDate(time_pattern,OUT_PATTERN,timestampStr));
                        break;
                    }
                }

            }
        }
        return timestamps;
    }

    /**
     * 将时间戳字符串转换为 Instant 类型
     * @param timestamp 时间戳字符串
     * @return Instant 类型的时间戳
     */
    public static Instant toInstant(String timestamp) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(OUT_PATTERN);
        LocalDateTime dateTime = LocalDateTime.parse(timestamp, formatter);
        return dateTime.atZone(ZoneOffset.UTC).toInstant();
    }


    /**
     * 按照规则格式化时间戳
     * @param inpattern 输入格式
     * @param outpattern 输出格式
     * @param timestampStr 原时间戳字符串
     * @return 格式化时间戳字符串
     */
    public static String formatDate(String inpattern,String outpattern,String timestampStr) {
        DateTimeFormatter inputFormatterDateTime = DateTimeFormatter.ofPattern(inpattern);
        DateTimeFormatter inputFormatterDate = DateTimeFormatter.ofPattern(inpattern);
        DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outpattern);
        LocalDateTime dateTime;
        try {
            dateTime = LocalDateTime.parse(timestampStr, inputFormatterDateTime);
        }catch (Exception e){
            LocalDate localDate = LocalDate.parse(timestampStr, inputFormatterDate);
            dateTime = localDate.atStartOfDay();
        }
        return dateTime.format(outputFormatter);
    }


    /**
     * 按照规则验证带分隔符的日期时间戳 yyyy-MM-dd-HH-mm-ss 是否有效
     * @param dateTimeStr 带分隔符的日期时间
     * @return 是否有效
     */
    public static boolean isValidTime(String dateTimeStr,String pattern) {
        LocalDateTime dateTime = null;
        if(dateTimeStr.length()==pattern.length()){
            try {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
                dateTime=LocalDateTime.parse(dateTimeStr, formatter);
            } catch (Exception e) {
                try {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
                    dateTime=LocalDate.parse(dateTimeStr, formatter).atStartOfDay();
                }catch (Exception e2){
                    return false;
                }
            }
        }
        if(dateTime==null) return false;
        int year = dateTime.getYear();
        int month = dateTime.getMonthValue();
        int day = dateTime.getDayOfMonth();
        int hour = dateTime.getHour();
        int minute = dateTime.getMinute();
        int second = dateTime.getSecond();
        return validRange(year,month,day,hour,minute,second);
    }

    /**
     * 按照规则验证时间戳是否合法
     * @param timestampStr 时间戳
     * @return 是否合法
     */
    public static boolean isValidTimestamp(String timestampStr) {
        if (16 < timestampStr.length() || 13 > timestampStr.length()) return false;
        try {
            long timestampMillis = Long.parseLong(timestampStr);
            Instant instant = Instant.ofEpochMilli(timestampMillis);
            ZonedDateTime dateTime = instant.atZone(ZoneOffset.UTC);

            int year = dateTime.getYear();
            int month = dateTime.getMonthValue();
            int day = dateTime.getDayOfMonth();
            int hour = dateTime.getHour();
            int minute = dateTime.getMinute();
            int second = dateTime.getSecond();
            return validRange(year,month,day,hour,minute,second);
        } catch (NumberFormatException e) {
            return false;
        }
    }
    private static Boolean validRange( int year, int month, int day, int hour, int minute, int second){
        // 验证时间范围
        if (year < 2000 || year > 2999) return false;//1000~99999
        if (month < 1 || month > 12) return false;
        if (day < 1 || day > 31) return false;
        if (hour < 0 || hour > 23) return false;
        if (minute < 0 || minute > 59) return false;
        if (second < 0 || second > 59) return false;
        return true;
    }
}
